#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstdlib>
#include <functional>
#include <sys/wait.h>
#include "protocol.hpp"
#include <cassert>
#include <functional>

namespace zxf
{
    enum zxf_err
    {
        USE_ERR = 1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR,
        ACCEPT_ERR,
        READ_ERR,
        WRITE_ERR,
        CONNECT_ERR,
        WAAITPID_ERR
    };
}

// 我们要把tcp服务器设计为一个对象

// 默认端口
static const uint16_t default_port = 11111;
// 默认ip
static const std::string default_ip = "0.0.0.0";
// 默认listen 参数
static const int gbacklog = 5;

namespace zxf
{

    class Http_server
    {

        // c++的函数包装器的使用
        // using func_t = std::function<bool (const HttpRequest &, HttpResponse &)>;

    public:
        // void func(const zxf::request &req, const zxf::response &resp)
        using func_t = std::function<bool(request &, response &)>;
        Http_server(const int16_t &port = default_port) // 构造函数
            : _port(port), _listensock(-1)
        {
        }
        // 服务器初始化
        void initServer()
        {
            _listensock = socket(AF_INET, SOCK_STREAM, 0);
            if (_listensock == -1)
            {
                std::cout << "socket error , exit" << std::endl;
                exit(1);
            }
            std::cout << "socket success!! " << std::endl;

            struct sockaddr_in local;
            socklen_t len = sizeof(local);
            ////先初始化为0
            memset(&local, 0, len);
            // bzero(&local, len);
            // 二选其一
            local.sin_family = AF_INET;         // 协议家族
            local.sin_port = htons(_port);      // 注意主机字节序转换为网络字节序
            local.sin_addr.s_addr = INADDR_ANY; // 直接绑定任意ip即可
            // local.sin_addr.s_addr = inet_addr(default_ip.c_str());
            int ret = bind(_listensock, (const struct sockaddr *)&local, len);
            if (ret == -1)
            {
                std::cout << "bind error , exit" << std::endl;
                exit(1);
            }
            std::cout << "bind success !!" << std::endl;

            // 设置监听状态 (listen)
            listen(_listensock, gbacklog);
            if (ret == -1)
            {
                exit(1);
            }
            std::cout << "listen success !!" << std::endl;
        }

        // 开始运行服务器
        void start(func_t func)
        {
            _func = func;
            // 设置回调函数

            for (;;)
            {
                struct sockaddr_in net;
                socklen_t len = sizeof(net);
                bzero(&net, len);
                int accept_fd = accept(_listensock, (struct sockaddr *)&net, &len);

                if (accept_fd == -1)
                {
                    std::cout << "accept error , exit" << std::endl;
                    continue;
                }
                std::cout << "accept success !! " << std::endl;

                int id = fork();
                if (id == 0)
                {
                    // 子进程
                    if (fork() > 0)
                    {
                        exit(0);
                    }
                    // 孙子进程 --->孤儿进程
                    hander(accept_fd);
                    // 我们让孙子进程去执行对应的程序我们不管进程返回信息
                    close(accept_fd);
                    exit(0);
                }

                int ret = waitpid(id, nullptr, 0); // 不关心进程退出信息
                if (ret < 0)
                {
                    std::cout << "waitpid error , exit" << std::endl;
                    exit(1);
                }
                std::cout << "waitpid success !!" << std::endl;
            }
        }

        // server建立链接之后的处理函数
        void hander(int sock)
        {
            // 服务器接受信息然后 返回
            for (;;)
            {
                // 读取http协议的request报文
                char buf[4096];
                request req;
                response resp;
                bzero(buf, 4096);
                int n = recv(sock, buf, 4096, 0);
                // 注意像recv read这样的接口是系统接口,一般不会给我们再末尾添加 '\0' ,有时候需要我们自己添加
                // fread 是系统接口就会自己添加 '\0'
                // 假设认为会读取完整一条报文
                if (n > 0)
                {
                    // 读取成功
                    buf[n] = 0;
                    req._buffer = buf;
                    req.parse();
                    _func(req, resp);
                    send(sock, resp._buffer.c_str(), resp._buffer.size(), 0); // 假如直接会发送完整
                }
            }
        }

    private:
        int16_t _port;   // 服务器绑定的port
        int _listensock; // 监听套接字
        func_t _func;
    };

} // namespace zxf  end!!
